package com.cat2bug.junit.clazz;

import com.cat2bug.junit.service.FunctionTestClassReportService;
import com.cat2bug.junit.service.ParameterService;
import com.cat2bug.junit.service.TestCaseService;
import com.cat2bug.junit.util.HttpUtils;
import com.cat2bug.junit.util.ParamMethodUtil;
import com.cat2bug.junit.util.UrlUtil;
import com.cat2bug.junit.vo.*;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.springframework.web.bind.annotation.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 添加测试http接口的方法
 * @author yuzhantao
 *
 */
public abstract class AbstractAddHttpAPIOfTestMethod extends AbstractAddMethodOfTestClass {
	protected Method srcMethod;

	public AbstractAddHttpAPIOfTestMethod(ITestClassFactory factory, String name, Method srcMethod, Class<?>[] paramesClasses,
			Map<Class<? extends Annotation>, Map<String, Object>> annoations) {
		super(factory, name, paramesClasses, annoations);
		this.srcMethod = srcMethod;
	}

	@Override
	public String body(CtClass ctClass) throws Exception {
		String url = null;
		List<HttpInterfaceParamVo> httpInterfaceParamVoList = new ArrayList<>();
		String srcUrl = HttpUtils.getUrl(this.srcMethod);
		if (srcUrl == null)
			return null;

		String methodName = "test" + this.srcMethod.getName().substring(0, 1).toUpperCase()
				+ this.srcMethod.getName().substring(1);
		// 创建测试方法
		CtMethod ctMethod = new CtMethod(CtClass.voidType, methodName, new CtClass[] {}, ctClass);
		ctMethod.setModifiers(Modifier.PUBLIC);

		// 向测试用例服务中添加方法信息
		ControllerTestMethod testMethod = new ControllerTestMethod(ctClass, ctMethod);
		List<TestParameter> testParameterList = new ArrayList<>();
		testMethod.setParameters(testParameterList);
		TestCaseService.getInstance().addTestMethod(testMethod);
		// 创建方法体
		StringBuffer body = new StringBuffer();
		body.append("\n{");
		body.append("\n java.util.Map params=new java.util.HashMap();");
		body.append("\n java.lang.Object requestBodyParam=null;");
		// 遍历参数
		ClassPool pool = ClassPool.getDefault();
		CtClass srcClass = pool.getCtClass(this.srcMethod.getDeclaringClass().getName()); // 获取原始类
		CtMethod srcMethod = srcClass.getDeclaredMethod(this.srcMethod.getName()); // 获取原始类方法
		MethodInfo methodInfo = srcMethod.getMethodInfo();
		CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
		if (codeAttribute != null) {
			LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
					.getAttribute(LocalVariableAttribute.tag);
			int paramLen = srcMethod.getParameterTypes().length; // 参数数量
			Object[][] ans = srcMethod.getParameterAnnotations(); // 获取参数注解
			int pos = Modifier.isStatic(srcMethod.getModifiers()) ? 0 : 1; // 非静态的成员函数的第一个参数是this
			for (int i = 0; i < paramLen; i++) {
				// 过滤掉不处理的类型
				if(ParameterService.getInstance().isFilter(srcMethod.getParameterTypes()[i].getName())){
					continue;
				}
				String paramName = attr.variableName(i + pos); // 参数名称
				String paramType = srcMethod.getParameterTypes()[i].getName(); // 参数类型
				if (ans[i] != null && ans[i].length > 0) {
					String paramMethodName = ParamMethodUtil.createMethodName(this.srcMethod.getName(),paramName,paramType);
					for (Object pa : ans[i]) {
						if (pa instanceof PathVariable) { // 如果是路径参数
							url = UrlUtil.compileUrl(srcUrl,(PathVariable)pa,paramName,paramMethodName); // 将路径中的变量替换成处理变量的方法
							break;
						} else if (pa instanceof RequestParam) { // 如果是请求参数
							body.append(String.format("\n params.put(\"%s\",this.%s());",paramName,paramMethodName));
							httpInterfaceParamVoList.add(new HttpInterfaceParamVo(HttpInterfaceParamType.RequestParam,paramName,paramType));
						} else if (pa instanceof RequestBody) { // 如果是Body请求参数
							body.append(String.format("\n requestBodyParam = this.%s();",paramMethodName));
							httpInterfaceParamVoList.add(new HttpInterfaceParamVo(HttpInterfaceParamType.RequestBody,paramName,paramType));
						}
					}
				} else {
					body.append(String.format("\n params.put(\"%s\",this.%s());",paramName,
							ParamMethodUtil.createMethodName(this.srcMethod.getName(),paramName,paramType)));
				}
			}

			if(url==null){
				url = UrlUtil.compileUrl(srcUrl,null,null,null);
			}
			body.append(String.format("\n String url = %s;",url));
			body.append(String.format(String.format("\n com.cat2bug.junit.vo.HttpInterfaceVo httpInterfaceVo = com.cat2bug.junit.service.FunctionTestClassReportService.getHttpInterface(\"%s\",\"%s\");",ctClass.getName(),methodName)));
			body.append(String.format("if(httpInterfaceVo!=null){"));
			body.append(String.format("httpInterfaceVo.setUrl(url);"));
			body.append(String.format("}"));
			body.append("\n " + HttpUtils.class.getName() + "."+this.getTestHttpMethodName()+"(mock,url,params,requestBodyParam);");
		}
		body.append("\n}");


		// 添加接口信息
		HttpInterfaceVo httpInterfaceVo = new HttpInterfaceVo();
		httpInterfaceVo.setClassName(ctClass.getName());
		httpInterfaceVo.setMethodName(methodName);
		httpInterfaceVo.setUrl(url);
		switch (this.getTestHttpMethodName()) {
			case "testPost":
				httpInterfaceVo.setMethodType(HttpInterfaceMethodType.POST);
				break;
			case "testPut":
				httpInterfaceVo.setMethodType(HttpInterfaceMethodType.PUT);
				break;
			case "testDelete":
				httpInterfaceVo.setMethodType(HttpInterfaceMethodType.DELETE);
				break;
			default:
				httpInterfaceVo.setMethodType(HttpInterfaceMethodType.GET);
				break;
		}
		httpInterfaceVo.setHttpInterfaceParamVoList(httpInterfaceParamVoList);
		FunctionTestClassReportService.addHttpInterface(httpInterfaceVo);

		return body.toString();
	}

	public abstract String getTestHttpMethodName();
}
